<script lang="ts" setup>
import { ref } from 'vue'

const sqlInput = ref('')
const protoOutput = ref('')
const errorMessage = ref('')
const isSuccess = ref(false)
const packageName = ref('pb')
const messageName = ref('')

// MySQL到Protobuf类型映射
const typeMapping: Record<string, string> = {
  // 整数类型
  'tinyint': 'int32',
  'smallint': 'int32',
  'mediumint': 'int32',
  'int': 'int32',
  'integer': 'int32',
  'bigint': 'int64',
  
  // 浮点类型
  'float': 'float',
  'double': 'double',
  'decimal': 'string', // Protobuf没有decimal，用string表示
  'numeric': 'string',
  
  // 字符串类型
  'char': 'string',
  'varchar': 'string',
  'text': 'string',
  'tinytext': 'string',
  'mediumtext': 'string',
  'longtext': 'string',
  
  // 二进制类型
  'binary': 'bytes',
  'varbinary': 'bytes',
  'blob': 'bytes',
  'tinyblob': 'bytes',
  'mediumblob': 'bytes',
  'longblob': 'bytes',
  
  // 日期时间类型
  'date': 'string',
  'time': 'string',
  'datetime': 'string',
  'timestamp': 'string',
  'year': 'int32',
  
  // 布尔类型
  'boolean': 'bool',
  'bool': 'bool',
  
  // JSON类型
  'json': 'string'
}

interface Column {
  name: string
  type: string
  nullable: boolean
  comment?: string
}

function parseCreateTable(sql: string): { tableName: string; columns: Column[] } {
  // 移除注释和多余空格
  const cleanSql = sql.replace(/--.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '').replace(/\s+/g, ' ').trim()
  
  // 提取表名
  const tableMatch = cleanSql.match(/CREATE\s+TABLE\s+(?:`?([^`\s]+)`?|([^\s(]+))/i)
  if (!tableMatch) {
    throw new Error('无法解析表名')
  }
  const tableName = tableMatch[1] || tableMatch[2]
  
  // 提取列定义
  const columnsMatch = cleanSql.match(/\(([\s\S]+)\)/)
  if (!columnsMatch) {
    throw new Error('无法解析列定义')
  }
  
  const columnsStr = columnsMatch[1]
  const columns: Column[] = []
  
  // 分割列定义（处理逗号分隔，但忽略括号内的逗号）
  const columnDefs = splitColumns(columnsStr)
  
  for (const columnDef of columnDefs) {
    const trimmed = columnDef.trim()
    if (!trimmed || trimmed.startsWith('PRIMARY KEY') || trimmed.startsWith('KEY') || 
        trimmed.startsWith('INDEX') || trimmed.startsWith('UNIQUE') || 
        trimmed.startsWith('FOREIGN KEY') || trimmed.startsWith('CONSTRAINT')) {
      continue
    }
    
    const column = parseColumn(trimmed)
    if (column) {
      columns.push(column)
    }
  }
  
  return { tableName, columns }
}

function splitColumns(str: string): string[] {
  const result: string[] = []
  let current = ''
  let depth = 0
  
  for (let i = 0; i < str.length; i++) {
    const char = str[i]
    if (char === '(') {
      depth++
    } else if (char === ')') {
      depth--
    } else if (char === ',' && depth === 0) {
      result.push(current.trim())
      current = ''
      continue
    }
    current += char
  }
  
  if (current.trim()) {
    result.push(current.trim())
  }
  
  return result
}

function parseColumn(columnDef: string): Column | null {
  // 匹配列定义：列名 类型 [约束] [COMMENT '注释']
  const match = columnDef.match(/^`?([^`\s]+)`?\s+([^\s(]+)(?:\([^)]+\))?(.*)$/i)
  if (!match) {
    return null
  }
  
  const name = match[1]
  const type = match[2].toLowerCase()
  const rest = match[3] || ''
  
  const nullable = !rest.toUpperCase().includes('NOT NULL')
  
  // 提取注释
  const commentMatch = rest.match(/COMMENT\s+['"]([^'"]*)['"]?/i)
  const comment = commentMatch ? commentMatch[1] : undefined
  
  return { name, type, nullable, comment }
}

function mysqlTypeToProto(mysqlType: string): string {
  // 处理带参数的类型，如 varchar(255)
  const baseType = mysqlType.split('(')[0].toLowerCase()
  return typeMapping[baseType] || 'string'
}

function toCamelCase(str: string): string {
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
}

function toPascalCase(str: string): string {
  const camelCase = toCamelCase(str)
  return camelCase.charAt(0).toUpperCase() + camelCase.slice(1)
}

function generateProtobuf(tableName: string, columns: Column[]): string {
  const messageNameToUse = messageName.value || toPascalCase(tableName)
  
  let proto = `syntax = "proto3";\n\n`
  
  if (packageName.value) {
    proto += `package ${packageName.value};\n\n`
  }
  
  proto += `// Generated from MySQL table: ${tableName}\n`
  proto += `message ${messageNameToUse} {\n`
  
  columns.forEach((column, index) => {
    const fieldNumber = index + 1
    const fieldName = toCamelCase(column.name)
    const fieldType = mysqlTypeToProto(column.type)
    
    if (column.comment) {
      proto += `  // ${column.comment}\n`
    }
    
    // 对于nullable字段，在proto3中使用optional（如果支持）或者添加注释
    if (column.nullable && fieldType !== 'string') {
      proto += `  // nullable field\n`
    }
    
    proto += `  ${fieldType} ${fieldName} = ${fieldNumber};\n`
    
    if (index < columns.length - 1) {
      proto += `\n`
    }
  })
  
  proto += `}\n`
  
  return proto
}

function convertToProtobuf() {
  try {
    if (!sqlInput.value.trim()) {
      errorMessage.value = '请输入MySQL CREATE TABLE语句'
      isSuccess.value = false
      return
    }
    
    const { tableName, columns } = parseCreateTable(sqlInput.value)
    
    if (columns.length === 0) {
      errorMessage.value = '未找到有效的列定义'
      isSuccess.value = false
      return
    }
    
    protoOutput.value = generateProtobuf(tableName, columns)
    errorMessage.value = `转换成功 ✓ (表: ${tableName}, 字段: ${columns.length}个)`
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `转换失败: ${(error as Error).message}`
    isSuccess.value = false
    protoOutput.value = ''
  }
}

function clearAll() {
  sqlInput.value = ''
  protoOutput.value = ''
  errorMessage.value = ''
  isSuccess.value = false
  messageName.value = ''
}

function copyToClipboard() {
  if (protoOutput.value) {
    navigator.clipboard.writeText(protoOutput.value).then(() => {
      errorMessage.value = '已复制到剪贴板 ✓'
      isSuccess.value = true
    })
  }
}

function loadSample() {
  sqlInput.value = `CREATE TABLE users (
  id bigint NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  username varchar(50) NOT NULL COMMENT '用户名',
  email varchar(100) NOT NULL COMMENT '邮箱地址',
  password varchar(255) NOT NULL COMMENT '密码',
  age int DEFAULT NULL COMMENT '年龄',
  is_active boolean DEFAULT true COMMENT '是否激活',
  balance decimal(10,2) DEFAULT 0.00 COMMENT '账户余额',
  avatar blob COMMENT '头像',
  created_at timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  updated_at timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (id),
  UNIQUE KEY uk_username (username),
  UNIQUE KEY uk_email (email)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';`
  
  packageName.value = 'pb'
  messageName.value = 'User'
}

function downloadProto() {
  if (!protoOutput.value) return
  
  const filename = `${messageName.value || 'message'}.proto`
  const blob = new Blob([protoOutput.value], { type: 'text/plain' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = filename
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
  URL.revokeObjectURL(url)
  
  errorMessage.value = `文件下载成功 ✓ (${filename})`
  isSuccess.value = true
}
</script>

<template>
  <div class="mysql-to-protobuf">
    <div class="config-section">
      <h3>配置选项</h3>
      <div class="config-row">
        <div class="config-item">
          <label>Package名称:</label>
          <input 
            v-model="packageName" 
            type="text" 
            placeholder="com.example"
            class="config-input"
          >
        </div>
        <div class="config-item">
          <label>Message名称:</label>
          <input 
            v-model="messageName" 
            type="text" 
            placeholder="自动从表名生成"
            class="config-input"
          >
        </div>
      </div>
    </div>

    <div class="controls">
      <button class="btn btn-primary" @click="convertToProtobuf">🔄 转换</button>
      <button class="btn btn-success" @click="copyToClipboard" :disabled="!protoOutput">📋 复制结果</button>
      <button class="btn btn-info" @click="downloadProto" :disabled="!protoOutput">💾 下载.proto</button>
      <button class="btn btn-warning" @click="loadSample">📝 加载示例</button>
      <button class="btn btn-danger" @click="clearAll">🗑️ 清空</button>
    </div>

    <div class="status" v-if="errorMessage" :class="{ 'error': !isSuccess, 'success': isSuccess }">
      {{ errorMessage }}
    </div>

    <div class="type-mapping">
      <details>
        <summary>MySQL到Protobuf类型映射表</summary>
        <div class="mapping-grid">
          <div class="mapping-header">
            <span>MySQL类型</span>
            <span>Protobuf类型</span>
          </div>
          <div v-for="(protoType, mysqlType) in typeMapping" :key="mysqlType" class="mapping-row">
            <span>{{ mysqlType }}</span>
            <span>{{ protoType }}</span>
          </div>
        </div>
      </details>
    </div>

    <div class="editor-container">
      <div class="editor-section">
        <h3>MySQL CREATE TABLE语句</h3>
        <textarea 
          v-model="sqlInput" 
          class="sql-input"
          placeholder="请输入MySQL CREATE TABLE语句...\n\n示例:\nCREATE TABLE users (\n  id bigint NOT NULL AUTO_INCREMENT,\n  username varchar(50) NOT NULL,\n  email varchar(100),\n  PRIMARY KEY (id)\n);"
          spellcheck="false"
        ></textarea>
      </div>

      <div class="editor-section">
        <h3>Protobuf消息定义</h3>
        <textarea 
          v-model="protoOutput" 
          class="proto-output"
          placeholder="转换后的Protobuf消息定义将显示在这里..."
          readonly
          spellcheck="false"
        ></textarea>
      </div>
    </div>
  </div>
</template>

<style scoped>
.mysql-to-protobuf {
  width: 100%;
}

.config-section {
  margin-bottom: 20px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.config-section h3 {
  margin: 0 0 15px 0;
  color: #fff;
  font-size: 1.1em;
}

.config-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

.config-item {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.config-item label {
  color: #ccc;
  font-size: 14px;
  font-weight: 500;
}

.config-input {
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 4px;
  color: #fff;
  font-size: 14px;
  outline: none;
}

.config-input:focus {
  border-color: rgba(255, 255, 255, 0.4);
}

.config-input::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.controls {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.2s ease;
  color: #fff;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  background: #007bff;
}

.btn-primary:hover:not(:disabled) {
  background: #0056b3;
}

.btn-success {
  background: #28a745;
}

.btn-success:hover:not(:disabled) {
  background: #1e7e34;
}

.btn-info {
  background: #17a2b8;
}

.btn-info:hover:not(:disabled) {
  background: #117a8b;
}

.btn-warning {
  background: #ffc107;
  color: #212529;
}

.btn-warning:hover:not(:disabled) {
  background: #e0a800;
}

.btn-danger {
  background: #dc3545;
}

.btn-danger:hover:not(:disabled) {
  background: #c82333;
}

.status {
  padding: 12px;
  border-radius: 6px;
  margin-bottom: 20px;
  font-weight: 500;
}

.status.error {
  background: rgba(220, 53, 69, 0.1);
  color: #dc3545;
  border: 1px solid rgba(220, 53, 69, 0.3);
}

.status.success {
  background: rgba(40, 167, 69, 0.1);
  color: #28a745;
  border: 1px solid rgba(40, 167, 69, 0.3);
}

.type-mapping {
  margin-bottom: 20px;
}

.type-mapping details {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.type-mapping summary {
  padding: 12px 15px;
  cursor: pointer;
  color: #fff;
  font-weight: 500;
  user-select: none;
}

.type-mapping summary:hover {
  background: rgba(255, 255, 255, 0.05);
}

.mapping-grid {
  padding: 15px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  max-height: 200px;
  overflow-y: auto;
}

.mapping-header {
  display: contents;
}

.mapping-header span {
  font-weight: bold;
  color: #fff;
  padding: 8px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 4px;
}

.mapping-row {
  display: contents;
}

.mapping-row span {
  padding: 6px 8px;
  color: #ccc;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 13px;
}

.mapping-row:nth-child(even) span {
  background: rgba(255, 255, 255, 0.02);
}

.editor-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  height: 500px;
}

.editor-section {
  display: flex;
  flex-direction: column;
}

.editor-section h3 {
  margin: 0 0 10px 0;
  color: #fff;
  font-size: 1.1em;
}

textarea {
  flex: 1;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 6px;
  padding: 15px;
  color: #fff;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.5;
  resize: none;
  outline: none;
}

textarea:focus {
  border-color: rgba(255, 255, 255, 0.4);
}

textarea::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.proto-output {
  background: rgba(0, 0, 0, 0.4);
}

@media (max-width: 768px) {
  .config-row {
    grid-template-columns: 1fr;
  }
  
  .editor-container {
    grid-template-columns: 1fr;
    height: auto;
  }
  
  .editor-section {
    height: 300px;
  }
  
  .controls {
    justify-content: center;
  }
  
  .mapping-grid {
    font-size: 12px;
  }
}
</style>